/*
 * @Author: TC
 * @Date: 2025-06-06 17:21:49
 * @Last Modified by: TC
 * @Last Modified time: 2025-06-06 17:57:39
 */
import { director, resources } from "cc";
import BASIS from "../Lib/Basis/basis_encoder.js";
import { DEV } from "cc/env";
import { BASIS_FORMAT, BasisFormat2GlFormat, Format } from "../Module/Ktx/KtxDefine";

/**
 * ktx下载器
 */
export class KtxManager {
    private _module: { BasisFile: any; KTX2File: any };

    public init(): Promise<void> {
        return new Promise((resove, reject) => {
            if (DEV) {
                resove();
                return;
            }
            this.initBasicModule().then(() => {
                resove();
            });
        });
    }

    /**
     * 解析basis格式文件
     * @param data
     * @returns
     */
    public parseBasis(data: ArrayBuffer): any {
        if (data instanceof ArrayBuffer) {
            data = new Uint8Array(data);
        }
        const basisFile = new this._module.BasisFile(new Uint8Array(data));
        var width = basisFile.getImageWidth(0, 0);
        var height = basisFile.getImageHeight(0, 0);
        var has_alpha = basisFile.getHasAlpha();

        if (!width || !height) {
            console.warn("Invalid .basis file");
            basisFile.close();
            basisFile.delete();
            return null;
        }

        let format = this.getSupportCompressFormat(width, height, has_alpha);

        if (!basisFile.startTranscoding()) {
            console.warn("startTranscoding failed");
            this._module.BasisFile.close();
            this._module.BasisFile.delete();
            return null;
        }

        const dstSize = basisFile.getImageTranscodedSizeInBytes(0, 0, format);
        const dst = new Uint8Array(dstSize);

        if (!basisFile.transcodeImage(dst, 0, 0, format, 1, 0)) {
            console.warn("transcodeImage failed");
            basisFile.close();
            basisFile.delete();
            return null;
        }
        basisFile.close();
        basisFile.delete();
        width = (width + 3) & ~3;
        height = (height + 3) & ~3;
        let imageData = {
            width: width,
            height: height,
            format: BasisFormat2GlFormat(format),
            data: dst,
        };
        return imageData;
    }
    /**
     * 初始化 Module
     */
    async initBasicModule() {
        let BasisModule: any;
        // Creator 3.4.1 无法正确加载Wasm文件 https://forum.cocos.org/t/topic/135776/3
        const wasmBinary = await new Promise<ArrayBuffer>((resolve, reject) => {
            resources.load("basis_encoder", (error, asset) => {
                if (error) {
                    reject(error);
                } else {
                    resolve(asset._nativeAsset as ArrayBuffer);
                }
            });
        });
        await new Promise((resolve) => {
            // BasisModule = { wasmBinary, onRuntimeInitialized: resolve };
            BasisModule = {
                wasmBinary,
                // wasmMemory: new WebAssembly.Memory({
                //     initial: 32, // 初始内存 32 pages（2MB）
                //     maximum: 128, // 限制最大 128 pages（8MB）
                // }),
                onRuntimeInitialized: resolve,
            };
            BASIS(BasisModule); // eslint-disable-line no-undef
        }).then(() => {
            BasisModule.initializeBasis();
        });
        this._module = BasisModule;
    }

    /**
     * 获取要转换的目标格式
     * @param width
     * @param height
     * @param has_alpha
     * @returns
     */
    private getSupportCompressFormat(width, height, has_alpha) {
        let format: BASIS_FORMAT;
        const getFormatFeatures = director.root.device.getFormatFeatures.bind(director.root.device);
        if (getFormatFeatures(Format.ASTC_RGBA_4X4)) {
            format = BASIS_FORMAT.cTFASTC_4x4;
        } else if (getFormatFeatures(Format.BC7)) {
            format = BASIS_FORMAT.cTFBC7;
        } else if (getFormatFeatures(Format.BC3)) {
            if (has_alpha) {
                format = BASIS_FORMAT.cTFBC3;
            } else {
                format = BASIS_FORMAT.cTFBC1;
            }
        } else if (getFormatFeatures(Format.PVRTC_RGBA4)) {
            if (has_alpha) {
                format = BASIS_FORMAT.cTFPVRTC1_4_RGBA;
            } else {
                format = BASIS_FORMAT.cTFPVRTC1_4_RGB;
            }

            if ((width & (width - 1)) != 0 || (height & (height - 1)) != 0) {
                console.error("ERROR: PVRTC1 requires square power of 2 textures");
            }
            if (width != height) {
                console.error("ERROR: PVRTC1 requires square power of 2 textures");
            }
        } else if (getFormatFeatures(Format.ETC_RGB8)) {
            format = BASIS_FORMAT.cTFETC1;
        } else {
            format = BASIS_FORMAT.cTFRGB565;
            // console.log('Decoding .basis data to 565');
        }

        if (!format) throw "error format!";
        return format;
    }
}
